package com.hmall.cart.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.api.item.ItemClient;
import com.hmall.api.item.dto.ItemDTO;
import com.hmall.cart.config.CartProperties;
import com.hmall.cart.domain.dto.CartFormDTO;
import com.hmall.cart.domain.po.Cart;
import com.hmall.cart.domain.vo.CartVO;
import com.hmall.cart.mapper.CartMapper;
import com.hmall.cart.service.ICartService;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;
import com.hmall.common.utils.CollUtils;
import com.hmall.common.utils.UserContext;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单详情表 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2023-05-05
 */
@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {

	private final ItemClient itemClient;
	private final CartProperties cartProperties;

	@Override
	public void addItem2Cart(CartFormDTO cartFormDTO) {
		// 1.获取登录用户
		Long userId = UserContext.getUser();

		// 2.判断是否已经存在
		if (checkItemExists(cartFormDTO.getItemId(), userId)) {
			// 2.1.存在，则更新数量
			baseMapper.updateNum(cartFormDTO.getItemId(), userId);
			return;
		}
		// 2.2.不存在，判断是否超过购物车数量
		checkCartsFull(userId);

		// 3.新增购物车条目
		// 3.1.转换PO
		Cart cart = BeanUtils.copyBean(cartFormDTO, Cart.class);
		// 3.2.保存当前用户
		cart.setUserId(userId);
		// 3.3.保存到数据库
		save(cart);
	}

	@Override
	public List<CartVO> queryMyCarts() {
		// 1.查询我的购物车列表
		List<Cart> carts = lambdaQuery().eq(Cart::getUserId, UserContext.getUser()).list();
		if (CollUtils.isEmpty(carts)) {
			return CollUtils.emptyList();
		}

		// 2.转换VO
		List<CartVO> vos = BeanUtils.copyList(carts, CartVO.class);

		// 3.处理VO中的商品信息
		handleCartItems(vos);

		// 4.返回
		return vos;
	}

	private void handleCartItems(List<CartVO> vos) {
		// 1.获取商品id
		Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());

		//# region
		// 2.查询商品
		// List<ItemDTO> items = null;

		// 方式一：通过Feign调用商品服务
		// String url = "http://localhost:9014/items?ids={ids}";

		// 方式二：通过 DiscoveryClient 提供的 api
		// List<ServiceInstance> instances = discoveryClient.getInstances("item-service");
		// // 随机选择一个实例
		// ServiceInstance serviceInstance = instances.get(new Random().nextInt(instances.size()));
		// String url = serviceInstance.getUri() + "/items?ids={ids}";

		// 方式三：通过 DiscoveryClient 提供的注解
		// String url = "http://item-service/items?ids={ids}";
		//
		// /**
		//  * exchange
		//  *
		//  * @return:
		//  * @param: url 请求地址
		//  * @param: method 请求方法
		//  * @param: requestEntity 请求实体
		//  * @param: responseType 响应类型
		//  * @param: uriVariables uri变量
		//  */
		// ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(url,
		// 	HttpMethod.GET,
		// 	null,
		// 	new ParameterizedTypeReference<List<ItemDTO>>() { },
		// 	CollUtils.join(itemIds, ",")
		// );
		// if (response.getStatusCode().is2xxSuccessful()) {
		// 	items = response.getBody();
		// }
		//# endregion

		// 方式四：通过 OpenFeign
		List<ItemDTO> items = itemClient.queryItemByIds(itemIds);

		if (CollUtils.isEmpty(items)) {
			return;
		}
		// 3.转为 id 到 item的map
		Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
		// 4.写入vo
		for (CartVO v : vos) {
			ItemDTO item = itemMap.get(v.getItemId());
			if (item == null) {
				continue;
			}
			v.setNewPrice(item.getPrice());
			v.setStatus(item.getStatus());
			v.setStock(item.getStock());
		}
	}

	@Override
	public void removeByItemIds(Long userId, Collection<Long> itemIds) {
		// 1.构建删除条件，userId和itemId
		QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
		queryWrapper.lambda().eq(Cart::getUserId, userId).in(Cart::getItemId, itemIds);
		// 2.删除
		remove(queryWrapper);
	}

	private void checkCartsFull(Long userId) {
		int count = lambdaQuery().eq(Cart::getUserId, userId).count();
		if (count >= cartProperties.getMaxAmount()) {
			throw new BizIllegalException(StrUtil.format("用户购物车课程不能超过{}", cartProperties.getMaxAmount()));
		}
	}

	private boolean checkItemExists(Long itemId, Long userId) {
		int count = lambdaQuery().eq(Cart::getUserId, userId).eq(Cart::getItemId, itemId).count();
		return count > 0;
	}
}
